package org.ehe.erp.service.product.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.ehe.common.core.exception.BusinessException;
import org.ehe.common.log.annotation.Log;
import org.ehe.common.mybatis.core.page.PageQuery;
import org.ehe.common.mybatis.core.page.TableDataInfo;
import org.ehe.common.satoken.utils.LoginHelper;
import org.ehe.erp.domain.product.ErpMaterial;
import org.ehe.erp.domain.product.ErpProduct;
import org.ehe.erp.domain.product.bo.ErpMaterialBo;
import org.ehe.erp.domain.product.vo.ErpMaterialVo;
import org.ehe.erp.mapper.product.MaterialMapper;
import org.ehe.erp.service.product.IErpProductService;
import org.ehe.erp.service.product.MaterialService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author :zhangnn
 * @className :MaterialService
 * @description: TODO
 * @date 2025-09-08 14:31:47
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class MaterialServiceImpl extends ServiceImpl<MaterialMapper, ErpMaterial> implements MaterialService {

    private final IErpProductService productService;
    @Override
    public TableDataInfo<ErpMaterialVo> getMaterialPage(ErpMaterialBo request, PageQuery pageQuery) {

        LambdaQueryWrapper<ErpMaterial> wrapper = Wrappers.<ErpMaterial>lambdaQuery()
            .eq(ErpMaterial::getDelFlag, 0)
            .like(StringUtils.isNotBlank(request.getMaterialCode()), ErpMaterial::getMaterialCode, request.getMaterialCode())
            .like(StringUtils.isNotBlank(request.getMaterialName()), ErpMaterial::getMaterialName, request.getMaterialName())
            .eq(request.getStatus() != null, ErpMaterial::getStatus, request.getStatus())
            .orderByAsc(ErpMaterial::getMaterialCode);


        // 转换为DTO
        IPage<ErpMaterialVo> erpMaterialVoIPage = this.baseMapper.selectVoPage(pageQuery.build(), wrapper);
        return TableDataInfo.build(erpMaterialVoIPage);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long addMaterial(ErpMaterialBo request) {
        // 1. 验证编码唯一性
        if (baseMapper.checkCodeExists(request.getMaterialCode(), LoginHelper.getTenantId(), null) > 0) {
            throw new BusinessException("材料编码已存在：" + request.getMaterialCode());
        }

        // 2. 验证名称唯一性
        if (baseMapper.checkNameExists(request.getMaterialName(), LoginHelper.getTenantId(), null) > 0) {
            throw new BusinessException("材料名称已存在：" + request.getMaterialName());
        }

        // 3. 创建材料对象
        ErpMaterial material = new ErpMaterial();
        BeanUtils.copyProperties(request, material);
        material.setTenantId(LoginHelper.getTenantId());
        material.setCreateBy(LoginHelper.getUsername());
        material.setCreateTime(new Date());

        // 4. 保存
        this.save(material);

        log.info("新增材料成功：id={}, code={}, name={}",
            material.getId(), material.getMaterialCode(), material.getMaterialName());

        return material.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateMaterial(ErpMaterialBo request) {
        // 1. 获取原记录
        ErpMaterial existingMaterial = this.getOne(
            Wrappers.<ErpMaterial>lambdaQuery()
                .eq(ErpMaterial::getId, request.getId())
                .eq(ErpMaterial::getTenantId, LoginHelper.getTenantId())
                .eq(ErpMaterial::getDelFlag, 0)
        );

        if (existingMaterial == null) {
            throw new BusinessException("材料不存在");
        }

        // 2. 验证编码唯一性（排除自己）
        if (baseMapper.checkCodeExists(request.getMaterialCode(), LoginHelper.getTenantId(), request.getId()) > 0) {
            throw new BusinessException("材料编码已存在：" + request.getMaterialCode());
        }

        // 3. 验证名称唯一性（排除自己）
        if (baseMapper.checkNameExists(request.getMaterialName(), LoginHelper.getTenantId(), request.getId()) > 0) {
            throw new BusinessException("材料名称已存在：" + request.getMaterialName());
        }

        // 4. 更新
        BeanUtils.copyProperties(request, existingMaterial, "id", "createTime", "createBy", "tenantId", "delFlag");
        existingMaterial.setUpdateBy(LoginHelper.getUsername());
        existingMaterial.setUpdateTime(new Date());

        this.updateById(existingMaterial);

        log.info("更新材料成功：id={}, code={}, name={}",
            existingMaterial.getId(), existingMaterial.getMaterialCode(), existingMaterial.getMaterialName());

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteMaterial(Long id) {
        ErpMaterial material = this.getOne(
            Wrappers.<ErpMaterial>lambdaQuery()
                .eq(ErpMaterial::getId, id)
                .eq(ErpMaterial::getTenantId, LoginHelper.getTenantId())
                .eq(ErpMaterial::getDelFlag, 0)
        );

        if (material == null) {
            throw new BusinessException("材料不存在");
        }

        // TODO: 检查是否被其他地方引用（如物料表）
         if (isMaterialInUse(id)) {
             throw new BusinessException("该材料正在使用中，不能删除");
         }

        // 逻辑删除
        material.setDelFlag("1");
        material.setUpdateTime(new Date());
        this.removeById(material);

        log.info("删除材料成功：id={}, code={}, name={}",
            material.getId(), material.getMaterialCode(), material.getMaterialName());

        return true;
    }

    /**
     * 判断是否使用中
     * @param id
     * @return
     */
    private boolean isMaterialInUse(Long id) {
        List<ErpProduct> list = productService.list(new LambdaQueryWrapper<ErpProduct>().eq(ErpProduct::getMaterial, id));
        if(list.size() > 0){
            return true;
        }
        return false;
    }

    /**
     * 获取物料详细信息
     * @param id
     * @return
     */
    @Override
    public ErpMaterialVo getMaterialDetail(Long id) {
        ErpMaterialVo material = this.baseMapper.selectVoOne(
            Wrappers.<ErpMaterial>lambdaQuery()
                .eq(ErpMaterial::getId, id)
                .eq(ErpMaterial::getTenantId, LoginHelper.getTenantId())
                .eq(ErpMaterial::getDelFlag, 0)
        );

        return material != null ? material : null;
    }

    @Override
    public List<ErpMaterialVo> getAllEnabledMaterials(String tenantId) {
        List<ErpMaterialVo> materials = this.baseMapper.selectVoList(
            Wrappers.<ErpMaterial>lambdaQuery()
                .eq(ErpMaterial::getTenantId, LoginHelper.getTenantId())
                .eq(ErpMaterial::getDelFlag, 0)
                .eq(ErpMaterial::getStatus, 1)
                .orderByAsc(ErpMaterial::getSortOrder)
                .orderByAsc(ErpMaterial::getMaterialCode)
        );

        return materials;
    }

    @Override
    public String getNextCode(String tenantId) {
        return baseMapper.getNextCode(LoginHelper.getTenantId());
    }

    @Override
    public boolean isCodeAvailable(String materialCode,Long excludeId) {
        return baseMapper.checkCodeExists(materialCode, LoginHelper.getTenantId(), excludeId) == 0;
    }

}
